﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Prism.Events;
using EventInfrastructure;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.ServiceLocation;
using ShellInfrastructure;
using ModuleOrderEdit.View;
using Microsoft.Practices.Unity;
using ServerConnection.ShopServiceReference;
using ServerConnection;
using ModulesInfrastructure.ViewModels;
using System.Windows.Input;
using Microsoft.Practices.Prism.Commands;
using System.ComponentModel;
using System.Reflection;


namespace ModuleOrderEdit.ViewModel
{
    /// <summary>
    /// ViewModel of the order for it's editing
    /// </summary>
    public class OrderEditViewModel : SharedViewModel, IOrderEditViewModel, IDataErrorInfo
    {
        #region Constructor

        /// <summary>
        /// The constructor of the OrderEditViewModel class 
        /// </summary>
        /// <param name="eventAggregator"></param>
        public OrderEditViewModel(IEventAggregator eventAggregator)
        {
            m_eventAggregator = eventAggregator;
            m_eventAggregator.GetEvent<OrderEditEvent>().Subscribe(onOrderEditEvent);
            m_ReserveOrderCommand = new DelegateCommand(onReserveOrderCommand);
            m_SaveChangesOrderCommand = new DelegateCommand(onSaveChangesOrderCommand);
            m_eventAggregator.GetEvent<AddProductInOrderEvent>().Subscribe(onAddProductInOrderEvent);
            m_eventAggregator.GetEvent<GetDeleteProductFromOrderEvent>().Subscribe(onGetDeleteProductFromOrderEvent);
            m_eventAggregator.GetEvent<OrderAddEvent>().Subscribe(onOrderAddEvent);                      
        }

        #endregion


        #region Public properties

        [Dependency]
        public IRegionManager RegionManager { get; set; }


        /// <summary>
        /// Current selectes order
        /// </summary>
        public OrderFull ShowOrder { get; private set; }


        /// <summary>
        /// Current selected product in the order
        /// </summary>
        public OrderPosition OnSelectedOrderPosition
        {
            get { return m_selectedOrderPosition; }
            set
            {
                m_selectedOrderPosition = value;
            }
        }


        /// <summary>
        /// Command of the order reserving
        /// </summary>
        public ICommand ReserveOrderCommand
        {
            get { return m_ReserveOrderCommand; }
            set
            {
                m_ReserveOrderCommand = value;
                RaisePropertyChanged(() => m_ReserveOrderCommand);
            }
        }


        /// <summary>
        /// Command for the saving order changes
        /// </summary>
        public ICommand SaveChangesOrderCommand
        {
            get { return m_SaveChangesOrderCommand; }
            set
            {
                m_SaveChangesOrderCommand = value;
                RaisePropertyChanged(() => m_SaveChangesOrderCommand);
            }
        }

        #endregion


        #region Private methods

        /// <summary>
        /// Adds the control to the right region
        /// </summary>
        /// <param name="flag">bool value</param>
        private void onOrderAddEvent(bool flag)
        {
            RegionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
            IRegion region = RegionManager.Regions[RegionNames.RightRegionName];
            region.Activate(ServiceLocator.Current.GetInstance<IOrderEditView>());

            this.ShowOrder = new OrderFull();
            RaisePropertyChanged(() => this.ShowOrder);
        }


        /// <summary>
        /// Gets full information of the selected order and loads it in right region
        /// </summary>
        /// <param name="id">Id of the order</param>
        private void onOrderEditEvent(long id)
        {
            RegionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
            IRegion region = RegionManager.Regions[RegionNames.RightRegionName];
            region.Activate(ServiceLocator.Current.GetInstance<IOrderEditView>());

            this.ShowOrder = new OrderFull();
            this.ShowOrder = Service.Instance.GetOrder(id, "eng");
            RaisePropertyChanged(() => this.ShowOrder);
        }


        /// <summary>
        /// Checks if it is posible to delete product from order
        /// </summary>
        /// <param name="flag">bool value</param>
        private void onGetDeleteProductFromOrderEvent(bool flag)
        {
            if (!ShowOrder.Status.Equals(OrderStatus.Closed))
            {
                if (m_selectedOrderPosition != null && m_selectedOrderPosition.Product != null)
                    onDeleteProductFromOrder(OnSelectedOrderPosition.Product.Id);
            }
        }


        /// <summary>
        /// Reserves selected product for current order
        /// </summary>
        private void onReserveOrderCommand()
        {
            if (OnSelectedOrderPosition != null)
            {
                m_selectedOrderPosition.CountUnreserved = Service.Instance.ReserveProduct(ShowOrder.Id, OnSelectedOrderPosition.Product.Id, OnSelectedOrderPosition.Count);
                RaisePropertyChanged(() => this.OnSelectedOrderPosition);
            }
        }


        /// <summary>
        /// Save changes to the order
        /// </summary>
        private void onSaveChangesOrderCommand()
        {
            ShowOrder = Service.Instance.UpdateOrder(ShowOrder);
            RaisePropertyChanged(() => this.ShowOrder);
            m_eventAggregator.GetEvent<RefreshOrderListEvent>().Publish(true);
        }


        /// <summary>
        /// Adds product to the order of creates a new order 
        /// </summary>
        /// <param name="productId">Id of the selected product</param>
        private void onAddProductInOrderEvent(long productId)
        {
            OrderFull temp;
            if (ShowOrder != null && ShowOrder.Id > 0)
            {
                temp = Service.Instance.AddProductToOrder(ShowOrder.Id, productId, 1);
            }
            else
            {
                Dictionary<long, int> products = new Dictionary<long, int>();
                products.Add(productId, 1);
                temp = Service.Instance.SetOrder(null, products, Service.PlaceId, Service.CurrentUser.Id);
            }
            if (temp != null)
                ShowOrder = temp;
            RaisePropertyChanged(() => this.ShowOrder);
            m_eventAggregator.GetEvent<RefreshOrderListEvent>().Publish(true);
        }


        /// <summary>
        /// Deletes the product from the order
        /// </summary>
        /// <param name="productId">Id of the selected product</param>
        private void onDeleteProductFromOrder(long productId)
        {
            ShowOrder = Service.Instance.DeleteProductFromOrder(ShowOrder.Id, productId, 1);
            RaisePropertyChanged(() => this.ShowOrder);
            m_eventAggregator.GetEvent<RefreshOrderListEvent>().Publish(true);
        }

        #endregion


        #region Private members

        private IEventAggregator m_eventAggregator;

        private ICommand m_ReserveOrderCommand;

        private ICommand m_SaveChangesOrderCommand;        

        /// <summary>
        /// Selected product in the order
        /// </summary>
        private OrderPosition m_selectedOrderPosition;        

        #endregion


        #region IDataErrorInfo Members

        public string Error
        {
            get { return "Invalid input"; }
        }

        public string this[string columnName]
        {
            get
            {
                string msg = null;
                PropertyInfo info = this.GetType().GetProperty(columnName);
                if (info != null)
                {
                    string value = info.GetValue(this, null) as string;
                    long? value2 = info.GetValue(this, null) as long?;
                    if (string.IsNullOrWhiteSpace(value) || value.Length < 1 || value2 < 1 || value2 > 1000)
                    {
                        return string.Format("{0} has incorrect data.", info.Name);
                    }

                }
                return msg;
            }
        }

        private string GetResult(string columnName)
        {
            PropertyInfo info = this.GetType().GetProperty(columnName);
            if (info != null)
            {
                string value = info.GetValue(this, null) as string;
                long? value2 = info.GetValue(this, null) as long?;
                if (string.IsNullOrWhiteSpace(value) || value.Length < 1 || value2 < 1 || value2 > 1000)
                {
                    return string.Format("{0} has incorrect data.", info.Name);
                }

            }
            return null;
        }
        #endregion
     
    }
}
